package com.ruyiadmin.springboot.controller.system;

import cn.hutool.extra.mail.MailUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruyiadmin.springboot.common.annotations.system.Log;
import com.ruyiadmin.springboot.common.annotations.system.Permission;
import com.ruyiadmin.springboot.common.core.business.enums.DeletionType;
import com.ruyiadmin.springboot.common.core.business.enums.OperationType;
import com.ruyiadmin.springboot.common.core.business.enums.ReadingStatus;
import com.ruyiadmin.springboot.common.core.system.entities.*;
import com.ruyiadmin.springboot.common.core.system.enums.DataType;
import com.ruyiadmin.springboot.common.core.system.enums.MessageType;
import com.ruyiadmin.springboot.common.core.system.enums.QueryMethod;
import com.ruyiadmin.springboot.domain.dto.system.SysAnnouncementDTO;
import com.ruyiadmin.springboot.domain.dto.system.SysNotificationDTO;
import com.ruyiadmin.springboot.domain.entity.system.*;
import com.ruyiadmin.springboot.service.iservices.system.ISysAddresseeService;
import com.ruyiadmin.springboot.service.iservices.system.ISysAnnouncementService;
import com.ruyiadmin.springboot.service.iservices.system.ISysAttachmentService;
import com.ruyiadmin.springboot.service.iservices.system.ISysUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.modelmapper.ModelMapper;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.jms.Topic;
import javax.validation.Valid;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

/**
 * <p>
 * 通知公告表 前端控制器
 * </p>
 *
 * @author RuYiAdmin
 * @since 2022-07-11
 */
@RestController
@RequestMapping("/AnnouncementManagement")
@Api(tags = "系统通知公告管理服务")
@RequiredArgsConstructor
@Slf4j
public class SysAnnouncementController {

    //region 通知公告服务私有属性

    private final ISysAnnouncementService announcementService;
    private final ModelMapper modelMapper;
    private final Topic topic;
    private final JmsMessagingTemplate jmsMessagingTemplate;
    private final ISysAddresseeService addresseeService;
    private final ISysUserService userService;
    private final ISysAttachmentService attachmentService;

    //endregion

    //region 查询通知公告列表

    @PostMapping("/Post")
    @ApiOperation(value = "查询通知公告列表")
    @Log(OperationType = OperationType.QueryList)
    @Permission(permission = "announcement:query:list")
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public QueryResult<SysAnnouncement> queryByPage(@RequestBody QueryCondition queryCondition)
            throws ExecutionException, InterruptedException {
        CompletableFuture<QueryResult<SysAnnouncement>> future = CompletableFuture.supplyAsync(() -> {
            QueryWrapper<SysAnnouncement> wrapper = new QueryWrapper<>();//设置条件
            queryCondition.getQueryWrapper(wrapper);//转化查询条件、转化排序条件
            Page<SysAnnouncement> page = new Page<>(queryCondition.getPageIndex(), queryCondition.getPageSize());//初始化page

            this.announcementService.page(page, wrapper);//执行查询
            long total = page.getTotal();//总数
            List<SysAnnouncement> rs = page.getRecords();//结果

            return QueryResult.success(total, rs);
        });
        return future.get();
    }

    //endregion

    //region 按编号获取通知公告

    @GetMapping("/GetById/{id}")
    @ApiOperation(value = "按编号获取通知公告")
    @Log(OperationType = OperationType.QueryEntity)
    @Permission(permission = "announcement:query:list,sys:announcement:query:list,notification:query:list")
    public ActionResult getById(@PathVariable("id") String id) throws ExecutionException, InterruptedException {
        CompletableFuture<ActionResult> future = CompletableFuture.supplyAsync(() ->
                ActionResult.success(this.announcementService.getById(id)));
        return future.get();
    }

    //endregion

    //region 添加通知公告

    @PostMapping("/Add")
    @ApiOperation(value = "添加通知公告")
    @Log(OperationType = OperationType.AddEntity)
    @Permission(permission = "announcement:add:entity")
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ActionResult add(@Valid @RequestBody SysAnnouncementDTO announcementDTO) {
        SysAnnouncement announcement = this.modelMapper.map(announcementDTO, SysAnnouncement.class);
        ActionResult actionResult = ActionResult.success(this.announcementService.save(announcement));
        try {
            //发送邮件与及时消息
            this.sengMailAndMessage(announcementDTO);
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
        }
        return actionResult;
    }

    //endregion

    //region 编辑通知公告

    @PutMapping("/Edit")
    @ApiOperation(value = "编辑通知公告")
    @Log(OperationType = OperationType.EditEntity)
    @Permission(permission = "announcement:edit:entity")
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ActionResult edit(@Valid @RequestBody SysAnnouncementDTO announcementDTO) {
        SysAnnouncement announcement = this.modelMapper.map(announcementDTO, SysAnnouncement.class);
        ActionResult actionResult = ActionResult.success(this.announcementService.updateById(announcement));

        //region 删除收件人

        QueryCondition queryCondition = new QueryCondition();
        queryCondition.setQueryItems(new ArrayList<>());
        queryCondition.getQueryItems().add(new QueryItem("BUSINESS_ID", DataType.Guid, QueryMethod.Equal, announcement.getId()));
        QueryWrapper<SysAddressee> wrapper = new QueryWrapper<>();
        queryCondition.getQueryWrapper(wrapper);
        List<SysAddressee> list = this.addresseeService.list(wrapper);
        list.forEach(t -> this.addresseeService.removeById(t.getId()));

        //endregion

        try {
            //发送邮件与及时消息
            this.sengMailAndMessage(announcementDTO);
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
        }
        return actionResult;
    }

    //endregion

    //region 批量删除通知公告

    @DeleteMapping("/Delete/{ids}")
    @ApiOperation(value = "批量删除通知公告")
    @Log(OperationType = OperationType.DeleteEntity)
    @Permission(permission = "announcement:del:entities")
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ActionResult deleteRange(@PathVariable("ids") String ids) {

        //删除数据
        List<String> array = Arrays.asList(ids.split(","));
        ActionResult actionResult = ActionResult.success(this.announcementService.removeByIds(array));

        //region 删除收件人

        array.forEach(t -> {
            QueryCondition queryCondition = new QueryCondition();
            queryCondition.setQueryItems(new ArrayList<>());
            queryCondition.getQueryItems().add(new QueryItem("BUSINESS_ID", DataType.Guid, QueryMethod.Equal, t));
            QueryWrapper<SysAddressee> wrapper = new QueryWrapper<>();
            queryCondition.getQueryWrapper(wrapper);
            List<SysAddressee> list = this.addresseeService.list(wrapper);
            list.forEach(a -> this.addresseeService.removeById(a.getId()));
        });

        //endregion

        return actionResult;
    }

    //endregion

    //region 获取通知公告收件人

    @GetMapping("/GetAnnouncementAddressee/{id}")
    @ApiOperation(value = "获取通知公告收件人")
    @Log(OperationType = OperationType.QueryList)
    @Permission(permission = "announcement:edit:entity")
    public QueryResult<SysAddressee> getAnnouncementAddressee(@PathVariable("id") String id)
            throws ExecutionException, InterruptedException {
        CompletableFuture<QueryResult<SysAddressee>> future = CompletableFuture.supplyAsync(() -> {
            QueryCondition queryCondition = new QueryCondition();
            queryCondition.setQueryItems(new ArrayList<>());
            queryCondition.getQueryItems().add(new QueryItem("BUSINESS_ID", DataType.Guid, QueryMethod.Equal, id));
            QueryWrapper<SysAddressee> wrapper = new QueryWrapper<>();
            queryCondition.getQueryWrapper(wrapper);
            List<SysAddressee> list = this.addresseeService.list(wrapper);
            return QueryResult.success(list.size(), list);
        });
        return future.get();
    }

    //endregion

    //region 查询公告列表

    @PostMapping("/GetAnnouncements")
    @ApiOperation(value = "查询公告列表")
    @Log(OperationType = OperationType.QueryList)
    @Permission(permission = "sys:announcement:query:list")
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public QueryResult<SysAnnouncement> getAnnouncements(@RequestBody QueryCondition queryCondition)
            throws ExecutionException, InterruptedException {
        CompletableFuture<QueryResult<SysAnnouncement>> future = CompletableFuture.supplyAsync(() -> {
            if (queryCondition.getQueryItems().size() <= 0) {
                queryCondition.setQueryItems(new ArrayList<>());
            }
            queryCondition.getQueryItems().add(new QueryItem("TYPE", DataType.Int, QueryMethod.Equal, 0));
            queryCondition.getQueryItems().add(new QueryItem("STATUS", DataType.Int, QueryMethod.Equal, 0));

            QueryWrapper<SysAnnouncement> wrapper = new QueryWrapper<>();//设置条件
            queryCondition.getQueryWrapper(wrapper);//转化查询条件、转化排序条件
            Page<SysAnnouncement> page = new Page<>(queryCondition.getPageIndex(), queryCondition.getPageSize());//初始化page

            this.announcementService.page(page, wrapper);//执行查询
            long total = page.getTotal();//总数
            List<SysAnnouncement> rs = page.getRecords();//结果

            return QueryResult.success(total, rs);
        });
        return future.get();
    }

    //endregion

    //region 查询通知列表

    @PostMapping("/GetNotifications")
    @ApiOperation(value = "查询通知列表")
    @Log(OperationType = OperationType.QueryList)
    @Permission(permission = "notification:query:list")
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public QueryResult<SysNotificationDTO> getNotifications(@RequestBody QueryCondition queryCondition) throws Exception {
        return this.announcementService.getNotifications(queryCondition);
    }

    //endregion

    //region 更改通知收件人阅读状态

    @GetMapping("/UpdateNotificationStatus/{notificationId}")
    @ApiOperation(value = "更改通知收件人阅读状态")
    @Log(OperationType = OperationType.EditEntity)
    @Permission(permission = "notification:query:list")
    public ActionResult updateNotificationStatus(@PathVariable("notificationId") String notificationId) throws Exception {
        return ActionResult.success(this.addresseeService.updateNotificationStatus(notificationId));
    }

    //endregion

    //region 发送邮件与及时消息

    static class Message {
        public String Id;
        public String Title;
    }

    private void sengMailAndMessage(SysAnnouncementDTO announcementDTO) {
        if (announcementDTO.getType() == 0 && announcementDTO.getStatus() == 0) {
            //region 发送及时消息

            SystemMessage msg = new SystemMessage();
            msg.setMessage("Announcement");
            msg.setMessageType(MessageType.Announcement);

            Message message = new Message();
            message.Title = announcementDTO.getTitle();
            msg.setObject(message);

            this.jmsMessagingTemplate.convertAndSend(topic, JSON.toJSONString(msg));

            //endregion
        } else if (announcementDTO.getType() == 1 && !StringUtils.isEmpty(announcementDTO.getAddressee())) {
            //region 发送邮件与及时消息

            String[] array = announcementDTO.getAddressee().split(",");
            for (String item : array) {
                SysAddressee addr = new SysAddressee();
                addr.setBusinessId(announcementDTO.getId());
                addr.setUserId(item);
                addr.setStatus(ReadingStatus.Unread.ordinal());
                addr.setBusinessId(announcementDTO.getId());
                this.addresseeService.save(addr);
            }

            //发送邮件
            if (announcementDTO.isSendMail() && announcementDTO.getStatus() == 0 && array.length > 0) {
                for (String item : array) {
                    SysUser user = this.userService.getById(item);
                    if (!StringUtils.isEmpty(user.getEmail())) {
                        //获取附件列表
                        List<SysAttachment> attachments = this.attachmentService.list();
                        attachments = attachments.stream().
                                filter(t -> t.getBusinessId().equals(announcementDTO.getId())).
                                filter(t -> t.getIsdel() == DeletionType.Undeleted.ordinal()).
                                collect(Collectors.toList());

                        //加载附件信息
                        File[] files = new File[attachments.size()];
                        for (int i = 0; i < attachments.size(); i++) {
                            files[i] = new File(attachments.get(i).getFilePath());
                        }

                        //发送邮件
                        MailUtil.send(
                                user.getEmail(),
                                announcementDTO.getTitle(),
                                announcementDTO.getContent(),
                                true,
                                files);

                        //region 发送及时消息

                        SystemMessage msg = new SystemMessage();
                        msg.setMessage("Notification");
                        msg.setMessageType(MessageType.Notification);

                        Message message = new Message();
                        message.Id = user.getId();
                        message.Title = announcementDTO.getTitle();
                        msg.setObject(message);

                        this.jmsMessagingTemplate.convertAndSend(topic, JSON.toJSONString(msg));

                        //endregion
                    }
                }
            }

            //endregion
        }
    }

    //endregion

}
